NestJS でテストを書くときは useMocker を使うと楽
皆さんテスト書いてますか? 僕は最近はあまり書けていません。
基本的な流れは
beforeEach で
対象クラスを包括する Module を createTestingModule を使って生成
本物の Module は使わず、テスト用 Module を作る
Module から対象のクラスを導出
各テストケースで導出したクラスに対してテストを実行
という感じで、依存がある場合は Module を作るときに imports なりをするのだが…
依存が多いと imports するのは手間だし、依存の依存は imports では解決してくれない!
providers で { providers: SomeService, useValue: new SomeService() } みたいなことをしないといけない
そんな面倒なことはしたくないので、useMocker を使って auto mocking で解決しよう!
これが最強(要出典)の auto mocking を使ったテストだ!
code:auto-mocking-test.spec.ts
import { Test, TestingModule } from '@nestjs/testing'
import { createMock } from '@golevelup/ts-jest'
import { TargetService } from './target.service.ts'
import { SomeRespository } from './some.repository.ts'
describe('TargetService', () => {
let service: TargetSerice
let repository: SomeRepository
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
TargetService,
{
providers: SomeRepository,
useValue: createMock<SomeRepository>({
$connect: jest.fn().mockReturnValue(true),
findMany: jest.fn(),
}),
}
]
})
.useMocker(() => createMock())
.compile()
service = module.get<TargetService>(TargetService)
repository = module.get(SomeRepository)
})
it('should be defined', () => {
expect(service).toBeDefined()
})
if('should be find many hogehoge', () => {
(repository.findMany as jest.Mock).mockImplementationOnce(({ limit }) => Array(limit).fill('hogehoge'))
const actual = service.hoge()
expect(actual).toHaveLength(5)
expect(repository.$connect).toHaveBeenCalled()
})
})
基本的には createTestingModule を使う時に useMocker で適当な mock factory を食べさせればいい
こうすることで、呼ばれるかも分からないような地獄みたいな数の依存もとりあえずモックでごまかせる
実装が必要な物は providers で個別にモックを生成して与える
内部実装は jest.fn() を使う
どのテストケースでも同じふるまいで良いのであればモックの内容まで書いても良い
テストケースごとに変えたい物は事前に jest.fn() だけ置いておき、各テストケースでふるまいを設定する
この方法だと事前に jest.fn() を置いてまわらないといけないのが面倒くさい、自動でやらせたい